import Entry from '../Entry';

import {singleDeduct, alternateDeduct} from './decompose';


// 我们有两种情况会用到Voucher：

// 1. 当我们读取序时帐并创建一条分录时
//    此时我们会直接使用构造函数。通过判断是否存在LineID来确定我们
//    是在创建一条凭证行还是在创建一个完整凭证。

// 2. 当我们汇总属于同一个凭证的若干行，并创建一条新的行时。
//    此时我们会使用静态方法from，在from中用到构造函数时可以保证lineID
//    是不存在的。

class Voucher extends Entry {

  constructor({year, month, billDate, desc, voucherType, voucherID, lineID, ...args}={}, opts){
    super(args, opts);

    this.billDate = billDate ?? new Date();

    this.year = year ?? this.billDate.getFullYear();
    this.month = month ?? this.billDate.getMonth();
    this.desc = desc;

    this.voucherID = lineID === undefined ? `${voucherID}` : `${this.year}-${this.month}-${voucherType ?? 0}-${voucherID}-${lineID}`;
  }

  copy(opts={}) {
    return new Voucher(this, opts);
  }

  add(voucher) {
    this.accrual.add(voucher.accrual);
  }

  static from(list, {voucherID, decompose=false, emptyIdentity=false, attr={}}={}) {

    if (list.some(entry => !(entry instanceof Voucher))) {
      throw Error('Voucher.from: voucher must be formed from list of Entry');
    }

    const voucher = new Voucher(list[0], {emptyAccrual: true, emptyIdentity});
    for (let entry of list) {
      voucher.add(entry);
      entry.move(voucher, {pushSide:'TAIL', withPath: false, withProto: false});
    }

    if (voucherID !== undefined) {
      voucher.voucherID = voucherID;
    }

    if (decompose) {
      voucher.decompose();
    }

    voucher.attr = attr;

    return voucher;
  }

  copy(){
    return new Voucher(this);
  }

  decompose({type='ALTERNATE', ...opts}={}) {

    this.succ.orderBy('voucherID');

    if (type === 'SINGLE') {
      this.succ = singleDeduct(this.succ, opts)
    } else if (type === 'ALTERNATE') {
      this.succ = alternateDeduct(this.succ);
    }

  }

  decomposeAgainst(list){
    if (list.some(entry => !(entry instanceof Voucher))) {
      throw Error('Voucher.decomposeAgainst: voucher must be formed from list of Entry');
    }

    const {decomp, rest} = this.accrual.decomposeAgainst(list.map(({accrual}) => accrual));
    
    return {
      decomp : decomp.map(accrual => new Voucher({...this, accrual})),
      rest: new Voucher(({...this, accrual: rest}))
    }

  }
}

export default Voucher;